home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / opbonus.arc / FBROWSE.ARC / FBROWSE.DOC < prev    next >
Text File  |  1991-03-20  |  67KB  |  1,679 lines

  1.  
  2.  
  3.               FBROWSE: Object-Oriented Browser for B-Tree Filer
  4.  
  5.                    Copyright (c) 1990 TurboPower Software
  6.                                  June 1990
  7.                                 Version 5.06
  8.  
  9.  
  10. ------- Overview -----------------------------------------------------------
  11.  
  12.  
  13. The main purpose of the FBROWSE unit is to merge the functionality of B-Tree
  14. Filer's BROWSER unit into an object based on Object Professional's
  15. CommandWindow. Besides making it easier to provide a consistent user interface
  16. throughout a program that uses both products, FBROWSE offers several other
  17. advantages over the BROWSER unit:
  18.  
  19.   - encapsulation of data allows multiple browsers to be active at once
  20.   - support for multi-line items
  21.   - built-in support for horizontal scrolling
  22.   - browse window can be moved, zoomed, or resized
  23.   - improved mouse and scroll bar support
  24.   - limits on rows and columns can be set at runtime
  25.   - scroll-by-page option
  26.   - refresh function hook allows browser to promptly detect and display
  27.     changes made at other workstations
  28.   - hook that allows the programmer to add incremental searching
  29.     capabilities
  30.  
  31. The FBrowser object implemented in FBROWSE.PAS also, of course, provides all
  32. of the other features inherited from its parents (hot spots, shadows,
  33. headers, etc.).
  34.  
  35. Important note: In order to compile FBROWSE.PAS, you must have version 5.05 or
  36. higher of B-Tree Filer, and version 1.01 or higher of Object Professional.
  37.  
  38.  
  39. ------- A Simple Example: FBSIMPLE -----------------------------------------
  40.  
  41.  
  42. The following is a simplistic demonstration program that works with the same
  43. files used by NETDEMO.PAS (from B-Tree Filer) and BTFDEMO.PAS (found on the
  44. Object Professional BONUS disk). It assumes that these files (ADDRESS.DAT and
  45. ADDRESS.IX) already exist and contain data. The purpose of the program is
  46. simply to show those steps that *must* be taken in any program that uses the
  47. FBrowser object implemented in FBROWSE. (Actually, in this case an object of
  48. type VBrowser is used, since ADDRESS.DAT contains variable-length records.)
  49.  
  50.  
  51. program FbSimple;
  52. uses
  53.   OpCrt, OpCmd, OpFrame, OpWindow, Filer, VRec, FBrowse;
  54. const
  55.   SectionLength = 140;
  56. type
  57.   PersonDef =
  58.     record
  59.       Dele             : LongInt;
  60.       FirstName, Name  : String[15];
  61.       Company, Address : String[25];
  62.       City             : String[15];
  63.       State            : String[2];
  64.       Zip              : String[10];
  65.       Telephone        : String[12];
  66.       NotesLen         : Word;
  67.       Notes            : array[1..932] of Char;
  68.     end;
  69. var
  70.   PS     : LongInt;
  71.   Pf     : IsamFileBlockPtr;
  72.   Person : PersonDef;
  73.   VB     : VBrowser;
  74.   DatLen : Word;
  75.  
  76.   {$F+}
  77.   procedure BuildItem(Row : Byte;
  78.                       var DatS;
  79.                       DatLen : Word;
  80.                       Ref : LongInt;
  81.                       Key : IsamKeyStr;
  82.                       var S : String;
  83.                       FBP : FBrowserPtr);
  84.     {-Return one row of an item to the browser in S}
  85.   var
  86.     P : PersonDef absolute DatS;
  87.   begin
  88.     {for this simple demo, just return the key}
  89.     S := Key;
  90.   end;
  91.  
  92. begin
  93.   {allocate buffer for variable-length records}
  94.   if not SetVariableRecBuffer(SectionLength) then
  95.     Halt;
  96.  
  97.   {allocate page stack}
  98.   PS := GetPageStack(20000);
  99.   if not IsamOK then
  100.     Halt;
  101.  
  102.   {open file block}
  103.   OpenFileBlock(Pf, 'ADDRESS');
  104.   if not IsamOK then
  105.     Halt;
  106.  
  107.   {initialize browser}
  108.   if not VB.Init(1, 1, 80, 25,  {window coordinates}
  109.                  Pf,            {fileblock pointer}
  110.                  1,             {key number}
  111.                  Person,        {record buffer}
  112.                  0,             {maximum number of rows in window}
  113.                  1,             {number of rows per item}
  114.                  30) then       {maximum number of columns per row}
  115.     Halt;
  116.   VB.SetBuildItemProc(BuildItem);
  117.   VB.fbOptionsOn(fbBuildOnKey);
  118.  
  119.   repeat
  120.     {process commands}
  121.     VB.Process;
  122.  
  123.     {read the current record}
  124.     case VB.GetLastCommand of
  125.       ccSelect, ccQuit, ccError : {ok} ;
  126.       else VB.GetCurrentRecord(Person, DatLen);
  127.     end;
  128.   until (VB.GetLastCommand = ccQuit) or (VB.GetLastCommand = ccError);
  129.  
  130.   {erase and destroy the browse window}
  131.   VB.Erase;
  132.   VB.Done;
  133.  
  134.   {close file block}
  135.   CloseFileBlock(Pf);
  136. end.
  137.  
  138.  
  139. The first order of business here is to initialize B-Tree Filer by calling
  140. SetVariableRecBuffer (needed only if the VREC unit is in use) and
  141. GetPageStack. If the program were a multi-user application, InitNetIsam would
  142. need to be called as well.
  143.  
  144. The second step is to open the Fileblock to be browsed. The timing of this
  145. step is extremely important. When instantiated, an FBrowser object needs to
  146. obtain information about the Fileblock to be browsed (the number of keys in
  147. the index file, whether it's a multi-user Fileblock, etc.), so the Fileblock
  148. must be opened successfully before we can initialize a browser for it.
  149.  
  150. The next task is to instantiate the browser by calling the Init constructor.
  151. As with all window-based objects, the first four parameters indicate the
  152. dimensions of the window. In this case, we've assumed an 80x25 screen. The
  153. fifth parameter is the IsamFileBlockPtr for the Fileblock just opened. The
  154. sixth parameter indicates which set of index keys to use. In this case, we've
  155. passed 1, so that the items will be arranged alphabetically by name (see the
  156. source for NETDEMO or FBDEMO). The seventh parameter names a record variable
  157. of the type stored in the data file. This variable will be used as a buffer by
  158. FBrowser when it reads records in from disk.
  159.  
  160. The eighth parameter indicates the maximum number of rows that will ever be
  161. displayed in the browse window. We've used 0 to indicate that we want the
  162. value to be calculated based on the height of the window. The ninth parameter
  163. indicates that each item (record) will be displayed on a single row of the
  164. window. The tenth and final parameter indicates the maximum number of columns
  165. on a given row (if this value is greater than the width of the window, the
  166. display may be scrolled horizontally). Although we could pass 0 here, we've
  167. used 30 to conserve memory, since that's the actual maximum and it's less than
  168. the width of the window. In this case, the savings is 1250 bytes: 25 rows * 50
  169. (80-30) columns. Note that FBrowser will automatically pad each row with
  170. blanks to the full width of the window if necessary.
  171.  
  172. The next step is the only other one that is required in all situations:
  173. calling SetBuildItemProc to specify the routine that, given a record in the
  174. database, will produce a string of text that can be displayed in the browse
  175. window to represent that "item." In keeping with the spirit of the program,
  176. the BuildItem routine shown here is extremely simple: it just returns the Key
  177. parameter, which contains a first and last name. A more typical routine would
  178. extract information from the DatS parameter (or rather from the PersonDef
  179. variable declared absolute on top of it). This step is unnecessary only in
  180. cases where a derived object type has overridden the BuildOneItem method.
  181.  
  182. The call to fbOptionsOn sets an option that is normally undesirable. The
  183. fbBuildOnKey option tells the browser that the build item routine needs only
  184. the index key to do its job, making it unnecessary to read the actual record
  185. in from the data file. Few applications can use this option, but those that
  186. can will benefit greatly in terms of performance. If and when you use it, do
  187. keep in mind that the DatS and DatLen parameters to the build item routine
  188. will contain meaningless data.
  189.  
  190. Now we're ready to start browsing. The main program loop just does two things
  191. over and over: it calls the Process method to display the browse window and
  192. process browsing commands, and it calls GetLastCommand to determine the
  193. command used to exit from the browser. In this simple case, only two exit
  194. commands are likely--ccQuit, which means quit browsing, and ccError, which
  195. means that a fatal error occurred while browsing--and the loop ends when
  196. either of them is returned.
  197.  
  198. The code that follows Process reads the currently highlighted record into
  199. Person. There's no need to do that in this sample program, but we've done so
  200. to illustrate an important point. There is only one case where it is safe to
  201. assume that the record buffer passed to the Init constructor contains the
  202. current record on return from Process: the case where GetLastCommand returns
  203. ccSelect. In all other cases, FBrowser leaves it up to you to decide whether
  204. or not the record should be loaded from disk.
  205.  
  206. NOTE: In this last regard the behavior of FBROWSE differs from that of the
  207. BROWSER unit, which always loads the current record before exiting from the
  208. Browse function. A similar difference in behavior exists in the handling of
  209. the special task hook: BROWSER always loads the current record before calling
  210. a special task routine, whereas FBrowser never does. The reason behind
  211. FBrowser's behavior in these two cases is simple: if the record doesn't need
  212. to be loaded, it's a waste of time to do it, and FBrowser has no way of
  213. knowing when you need it loaded and when you don't.
  214.  
  215. The program ends with some basic cleanup code. The browse window is erased
  216. and destroyed, and the Fileblock being browsed is closed.
  217.  
  218. Although this is an extremely atypical example, it does show the basic steps
  219. involved in setting up a browse window and examining the contents of a data
  220. file with it. The next section discusses a more typical one.
  221.  
  222.  
  223. ------- A Comprehensive Example: FBDEMO ------------------------------------
  224.  
  225.  
  226. A more realistic example program is FBDEMO.PAS, which is based on the BTFDEMO
  227. program on the Object Professional BONUS disk, which is in turn based on the
  228. NETDEMO program in B-Tree Filer. Like FBSIMPLE, FBDEMO works with ADDRESS.DAT
  229. and ADDRESS.IX. Unlike FBSIMPLE, it allows records to be added, deleted, and
  230. modified as well as displayed.
  231.  
  232. FBDEMO demonstrates most of the features of FBROWSE that distinguish it from
  233. BROWSER:
  234.  
  235.   - The <F6> command allows the user to specify record filtering criteria
  236.   - The <AltM> command allows the user to move the browse window
  237.   - The <AltR> command allows the user to resize the browse window
  238.   - The <AltZ> command allows the user to zoom the browse window
  239.   - When run on a network, the refresh function hook is used to automatically
  240.     update the display when another workstation adds, deletes, or modifies a
  241.     record in the database.
  242.   - The RowsPerItem constant in the source code may be increased, allowing you
  243.     to see what multi-line items look like.
  244.   - By defining TestStream in the source code, you can test FBROWSE's streams
  245.     support.
  246.  
  247. Because it illustrates so many of the basic features of FBROWSE, FBDEMO.PAS
  248. should be considered a useful supplement to the documentation provided here,
  249. and it is referred to frequently in the sections that follow.
  250.  
  251.  
  252. ------- Miscellaneous Issues -----------------------------------------------
  253.  
  254. The fbForceUpdate Option
  255. ------------------------
  256. The fbForceUpdate option is VERY IMPORTANT. It MUST be set--BY YOU--before you
  257. call either Draw or Process after adding, deleting, or modifying a record in
  258. the data file being browsed:
  259.  
  260.   FB.fbOptionsOn(fbForceUpdate);
  261.  
  262. This tells the browser that it needs to rebuild the current page before
  263. displaying it. See FBDEMO.PAS for examples of cases where fbForceUpdate needs
  264. to be set.
  265.  
  266. Variable-length Records
  267. -----------------------
  268. The FBrowser object works only with Fileblocks containing fixed-length
  269. records. To browse through a file containing variable-length records, you must
  270. use the VBrowser object instead, as was done in FBSIMPLE and FBDEMO. This
  271. child object simply overrides the FBrowser's GetRecord method, routing all
  272. requests to read a record to the appropriate routine in the VREC unit.
  273.  
  274. Rows Longer than 255 Characters
  275. -------------------------------
  276. The FBrowser object stores the data to be displayed for a given row of an item
  277. in a string of up to 255 characters. In cases where that data exceeds 255
  278. characters, it is usually best to display it on multiple rows. It is possible,
  279. however, to set the maximum number of columns to a value greater than 255. If
  280. this is done, the FBrowser will have to check, when scrolling the display
  281. horizontally, to be certain that the necessary columns of data are loaded into
  282. memory. If they're not, the build item routine will be called to build new
  283. sets of strings for all the items, containing the data that is needed.
  284.  
  285. What the build item routine needs to do in such cases is to call the
  286. FBrowser's GetFirstCol method to see which columns of data are desired. For
  287. example, if GetFirstCol returns 1 (as it would initially), then the build item
  288. routine should provide columns 1-255. If GetFirstCol returns 200, then the
  289. build item routine should supply columns 200-354. That is, if the maximum
  290. number of columns is greater than 255, the build item routine should always
  291. return 255 columns of data starting at the column indicated by GetFirstCol. It
  292. may return fewer than 255 columns only if the starting column is within 255
  293. characters of the end of the row.
  294.  
  295. Keep in mind when using this facility that the records for each item being
  296. displayed must be reread from disk before the build item procedure is called.
  297. Consequently, there is a performance penalty to be paid when scrolling the
  298. display horizontally. That is one of the reasons why we said that the multiple
  299. rows approach is generally preferable to setting the maximum number of columns
  300. to a value greater than 255.
  301.  
  302. Programmer's Hooks
  303. ------------------
  304. The FBrowser provides a variety of programmer's hooks that allow you to
  305. easily customize it for a particular application. See the entries for the
  306. following methods:
  307.  
  308.   - CharHook
  309.   - GetRecord
  310.   - SetBuildItemProc
  311.   - SetFilterFunc
  312.   - SetPreMoveProc
  313.   - SetRefreshFunc
  314.   - SetScreenUpdateProc
  315.   - SetSpecialTaskProc
  316.  
  317. Special Issues in Multi-user Applications
  318. -----------------------------------------
  319. One problem that commonly occurs when browsing through a data file in a
  320. multi-user application is The Full Keyboard Buffer Problem. If you hold down
  321. one of the cursor keys (e.g. <Up>) for too long, the browser can appear to
  322. hang the machine as it tries repeatedly to scroll the display even though
  323. there are no records beyond the current one. The fbFlushKbd option allows you
  324. to minimize the effects of this problem by flushing the keyboard buffer when a
  325. request to scroll the display fails.
  326.  
  327. A more serious issue is that of keeping the screen up-to-date, since another
  328. workstation can make a change that affects the records displayed on the
  329. current workstation. FBrowser deals with this issue in two ways. First, when
  330. the ccSelect command is issued, it checks to make sure that the selected
  331. record still exists. If it doesn't, a warning error is generated and the
  332. screen is redrawn.
  333.  
  334. Second, it provides the SetRefreshFunc hook, which allows you to specify a
  335. function that is called by Process just before it checks for another command.
  336. If the function returns True, Process will rebuild the display. Two ready-made
  337. refresh functions are provided that approach the problem in slightly different
  338. ways, RefreshAtEachCommand and RefreshPeriodically. The FBDEMO program also
  339. demonstrates a third technique that relies on Novell's semaphore services. The
  340. chief advantage of this technique is that it provides virtually instantaneous
  341. updates to a browser's display when another workstation modifies a Fileblock,
  342. without generating a significant amount of network traffic. The chief
  343. disadvantage of the technique is that it is less transparent than the others,
  344. since it requires you to keep the semaphores up to date when adding,
  345. modifying, or deleting records.
  346.  
  347. In any case, you can use one of the refresh functions we've provided, or you
  348. can write your own, or you can ignore the problem entirely. The choice is
  349. yours. But we highly recommend that you use some kind of refresh function in
  350. any multi-user application that you write.
  351.  
  352. Yet another problem can occur if a workstation locks a Fileblock while the
  353. current one is in the middle of refreshing its display. If this happens (and
  354. the build item routine called by the browser is written properly), the browse
  355. window will display a single item marked as a locked record. (FBDEMO uses
  356. sequences of asterisks to indicate locked records.) The best way to avoid this
  357. problem is to use the fbUseReadLock option, which tells the FBrowser to
  358. read-lock the Fileblock before it starts reading records. This insures that no
  359. other workstation will be able to lock the browser out of the Fileblock while
  360. it is trying to refresh the screen or scroll the display.
  361.  
  362. Of course, there's no guarantee that the current workstation will be able to
  363. read-lock the Fileblock on the first try. For this and other reasons, FBrowser
  364. provides the SetRetries method, which allows you to specify the number of
  365. times that it should retry a FILER I/O call that has failed due to a lock
  366. error. The default setting of 50 should be appropriate for most applications,
  367. but a higher setting may be needed on large networks where many users might be
  368. modifying the same Fileblock simultaneously.
  369.  
  370. Errors and Error Handling
  371. -------------------------
  372. FBROWSE defines the following error codes in addition to those defined in
  373. the OPROOT unit of Object Professional:
  374.  
  375.   ecWinTooSmall     = 06000; {init error--window/max rows too small}
  376.   ecNoIndex         = 06001; {init error--Fileblock is not indexed}
  377.   ecIsamError       = 06002; {fatal Isam error--IsamError has actual code}
  378.   ecNoKeysFound     = 06003; {no keys found in requested range}
  379.   ecRecordGone      = 06004; {tried to select record that no longer exists}
  380.   ecRecordLocked    = 06005; {tried to select record and lock error occurred}
  381.   ecFileBlockLocked = 06006; {non-fatal error due to locked fileblock}
  382.  
  383. The first two errors can occur only in a constructor. The ecWinTooSmall error
  384. will occur if either the height of the window or the maximum number of rows is
  385. less than the number of rows per item. The ecNoIndex error will occur if you
  386. try to browse a Fileblock that is not indexed. The ecIsamError code indicates
  387. that a fatal FILER I/O error has occurred. FILER's IsamError variable contains
  388. the actual error code.
  389.  
  390. The ecNoKeysFound error occurs when the browser is unable to find any
  391. records to display. It is classified as "fatal," because in most cases it
  392. is. But in two cases it may not be: 1) the case where the cause of the error
  393. was simply that SetKeyRange had been calling using a range that was too
  394. narrow, and the range can be reset, or 2) the case where the cause is a
  395. filter function that can be deactivated. The latter case can be seen in
  396. FBDEMO.PAS, which corrects the problem by calling the browser's ClearErrors
  397. method and then deactivating the filter.
  398.  
  399. The last three errors can occur only in multi-user applications, in cases
  400. where another workstation has deleted the record just selected by the user
  401. (ecRecordGone), a lock prevents access to it (ecRecordLocked), or a fileblock
  402. lock prevents the browse window from being drawn completely. These three
  403. errors are always classifies as warnings.
  404.  
  405. Streams
  406. -------
  407. Like all other CommandWindow-based objects, an FBrowser/VBrowser may be
  408. stored in and reloaded from a stream, and the steps required are essentially
  409. identical to those for other window objects. You absolutely must, however,
  410. register two pointers before loading/storing a browser: the IsamFileBlockPtr
  411. and the address of the record buffer passed to the object's constructor.
  412.  
  413. FBrowser's Store method saves all the data associated with the FBrowser
  414. itself, including the key and reference number for the currently highlighted
  415. record, but it does not save any of the data associated with the Fileblock
  416. being browsed. That Fileblock must be opened, and its address registered with
  417. the stream, both before the FBrowser is stored in the stream and before it is
  418. reloaded.
  419.  
  420. See the InitBrowser routine in FBDEMO.PAS for an example of how to store a
  421. browser in a stream and reload it.
  422.  
  423.  
  424. ------- The Help File: FBROWSE.TXT -----------------------------------------
  425.  
  426.  
  427. FBROWSE.TXT is intended to be merged with the help files for B-Tree Filer
  428. and/or Object Professional, allowing you to obtain popup help on FBROWSE using
  429. our POPHELP utility.
  430.  
  431. To combine help files, you should use a text editor to modify the main text
  432. file of one of the help databases. Let's say that you want to combine Object
  433. Professional's help with the help for FBROWSE. To do so, you would edit
  434. OPRO.TXT and add FBROWSE.TXT to the list of included help files. Just prior to
  435. the INCLUDE directive for FBROWSE.TXT, you would insert an additional line
  436. with a !BIAS directive. The BIAS directive specifies how much to offset the
  437. topic numbers for all topics that follow. As this is written, there are 2813
  438. topics in the OPRO help file, so the merged OPRO.TXT would look something like
  439. the following:
  440.  
  441. ...
  442. !INCLUDE OPSWAP1.TXT
  443. !INCLUDE OPTSR.TXT
  444. !INCLUDE OPWINDOW.TXT
  445. ;
  446. ;highest topic number used 2813
  447. ;
  448. !BIAS 2813
  449. ;
  450. !INCLUDE FBROWSE.TXT
  451.  
  452. You would then use MAKEHELP to recompile the combined help database:
  453.  
  454.    MAKEHELP /Q OPRO
  455.  
  456.  
  457. ------- Commands  ----------------------------------------------------------
  458.  
  459.  
  460. The commands available while browsing are arranged by category in the list
  461. below. In each case the first line gives the name of the command, followed
  462. by the key(s) to which it is normally assigned. The second and following
  463. lines give a brief description of the command.
  464.  
  465.  
  466. ccLeft         <Left>, <CtrlS>
  467. Scroll window left 1 column.
  468.  
  469. ccRight        <Right>, <CtrlD>
  470. Scroll window right 1 column.
  471.  
  472. ccHome         <Home>, <CtrlQ><S>
  473. Scroll window to column 1.
  474.  
  475. ccEnd          <End>, <CtrlQ><D>
  476. Scroll window to rightmost column, so that the end of each row is displayed.
  477.  
  478. ccUp           <Up>, <CtrlE>, <CtrlW>
  479. Scroll window up one item.
  480.  
  481. ccDown         <Down>, <CtrlX>, <CtrlZ>
  482. Scroll window down one item.
  483.  
  484. ccPageUp       <PgUp>, <CtrlR>
  485. Scroll window up one page.
  486.  
  487. ccPageDn       <PgDn>, <CtrlC>
  488. Scroll window down one page.
  489.  
  490. ccFirstRec     <CtrlPgUp>, <CtrlQ><R>
  491. Scroll to first record in file.
  492.  
  493. ccLastRec      <CtrlPgDn>, <CtrlQ><C>
  494. Scroll to last record in file.
  495.  
  496. ccPlus         <+>
  497. Rebuild and redisplay the current page.
  498.  
  499. ccSelect       <Enter>, <CtrlM>
  500. Select the currently highlighted item.
  501.  
  502. ccQuit         <CtrlBreak>, <Esc>, <ClickRight>
  503. Quit browsing.
  504.  
  505. ccHelp         <F1>, <ClickBoth>
  506. Help. If a user-written help routine has been established by calling
  507. FBrowserCommands.SetHelpProc, pressing <F1> will call that routine; otherwise
  508. this command does nothing. If there is a help procedure, the FBrowser will
  509. pass it the following three parameters: ucFBrowser, @Self, and the value
  510. designated as the window's help index (see CommandWindow.SetHelpIndex), which
  511. defaults to 0.
  512.  
  513. ccMouseSel     <ClickLeft>
  514. Move the highlight bar to the position indicated by the mouse, if possible. If
  515. the highlight bar is already over the indicated item, it will be selected,
  516. just as it would if <Enter> were pressed. This command may also be used to
  517. scroll the display by clicking on a scroll bar.
  518.  
  519.  
  520. ------- Declarations -------------------------------------------------------
  521.  
  522.  
  523. Constants
  524.  
  525.     BadFBrowserOptions : LongInt =
  526.       fbLockPending+fbForceRedraw+fbIsNet+fbInProcess;
  527.  
  528.   Options that exist for internal use, and may not be altered by calling
  529.   fbOptionsOn or fbOptionsOff.
  530.  
  531.     ccFirstRec  = ccTopOfFile; {Move cursor to first record}
  532.     ccLastRec   = ccEndOfFile; {Move cursor to last record}
  533.     ccPlus      = ccToggle;    {Rebuild and redraw current page}
  534.     ccTask0     = 180;         {user-defined task commands}
  535.     ...
  536.     ccTask19    = 199;
  537.  
  538.   Command codes unique to FBROWSE. (See the section on Commands, above.)
  539.  
  540.     DefFBrowserOptions : LongInt = fbMousePage+fbDrawActive+fbAutoScale;
  541.  
  542.   The default options for an FBrowser or VBrowser.
  543.  
  544.     DefRetriesOnLock : Integer = 50;
  545.  
  546.   Default number of times to retry following a lock error.
  547.  
  548.     ecWinTooSmall     = 06000; {init error--window/max rows too small}
  549.     ecNoIndex         = 06001; {init error--Fileblock is not indexed}
  550.     ecIsamError       = 06002; {fatal Isam error--IsamError has actual code}
  551.     ecNoKeysFound     = 06003; {no keys found in requested range}
  552.     ecRecordGone      = 06004; {tried to select record that no longer exists}
  553.     ecRecordLocked    = 06005; {tried to select record and lock error occurred}
  554.     ecFileBlockLocked = 06006; {non-fatal error due to locked fileblock}
  555.  
  556.   Codes for errors reported only by FBrowser-based objects.
  557.  
  558.     emIsamError    : string[40] = 'Fatal error accessing data or index file';
  559.     emNoKeysFound  : string[35] = 'No records found in specified range';
  560.     emRecordGone   : string[32] = 'Selected record no longer exists';
  561.     emRecordLocked : string[40] = 'Lock error while reading selected record';
  562.     emFileBlockLocked : string[14] = 'File is locked';
  563.  
  564.   The default error messages corresponding to the ecIsamError, ecNoKeysFound,
  565.   ecRecordGone, ecRecordLocked, and ecFileBlockLocked errors, respectively.
  566.  
  567.     fbScrollByPage   = $00000001; {scroll by page on Up/Down?}
  568.     fbMousePage      = $00000002; {clicking on scroll bar scrolls by page}
  569.     fbDrawActive     = $00000004; {Draw and Process leave sel item visible}
  570.     fbUseReadLock    = $00000008; {use read locks while building pages?}
  571.     fbAutoScale      = $00000010; {scale scroll bar based on low/high keys?}
  572.     fbForceUpdate    = $00000020; {force the screen to be updated}
  573.     fbFlushKbd       = $00000040; {flush keyboard buffer at boundaries}
  574.     fbBellOnFlush    = $00000080; {ring bell when flushing?}
  575.     fbBuildOnKey     = $00000100; {build item function needs only the key}
  576.     fbLockPending    = $10000000; {internal flags}
  577.     fbForceRedraw    = $20000000;
  578.     fbIsNet          = $40000000;
  579.     fbInProcess      = $80000000;
  580.  
  581.   These are the options that affect the behavior of an FBrowser.
  582.   fbScrollByPage affects the vertical scrolling behavior of an FBrowser when
  583.   the cursor is moved (using <Up> or <Down>) to an item not currently on
  584.   screen. If the option is off, the window will be scrolled only enough to
  585.   display the new item. If it is on, the window will be scrolled one full
  586.   page. fbMousePage determines what happens when the user clicks on the up and
  587.   down arrows of a scroll bar. If the option is off, the highlight will be
  588.   moved up or down by a single item; if it is on, the highlight will be moved
  589.   up or down one full page.
  590.  
  591.   If the fbDrawActive option is on, the current item will be highlighted at
  592.   all times; if it is off, the item will be highlighted only while the Process
  593.   method is active. If the fbUseReadLock option is on, the Fileblock in use
  594.   will be read-locked while building pages and scrolling. The fbAutoScale
  595.   option affects the behavior of vertical scroll bars in cases where a low and
  596.   high key have been specified with SetKeyRange. If it is on, the scroll bar's
  597.   scale is based on the positions within the current index of the first and
  598.   last record within the range. If it is off, the scale is based on the total
  599.   number of records in the current index. The fbForceUpdate option must be set
  600.   any time that you call either Draw or Process after adding, deleting, or
  601.   modifying a record in the data file being browsed.
  602.  
  603.   The fbFlushKbd and fbBellOnFlush options are intended primarily for use in
  604.   multi-user applications, to avoid the common problem that occurs when the
  605.   user holds down one of the cursor keys too long. When the end of the
  606.   database is reached, the browser will appear to hang because it's spending
  607.   all of its time processing commands that don't affect the display. The
  608.   fbFlushKbd option simply tells FBrowser to try to avoid this problem by
  609.   flushing the keyboard buffer when a cursor command fails to scroll the
  610.   display. The fbBellOnFlush option tells it to "ring the bell" each time a
  611.   keystroke is flushed from the keyboard buffer. The fbBuildOnKey option tells
  612.   the browser that the build item routine can do its job given only an index
  613.   key, and doesn't need the actual record.
  614.  
  615.   The remaining options--fbLockPending, fbForceRedraw, fbIsNet, and
  616.   fbInProcess--are intended strictly for internal use.
  617.  
  618.     FBrowserKeyMax = 200;
  619.     FBrowserKeyID  : string[13] = 'fbrowser keys';
  620.     FBrowserKeySet : array[0..FBrowserKeyMax] of Byte = (...);
  621.     FBrowserCfgEnd : Byte = 0;
  622.  
  623.   FBrowserKeyId is an ID string used to mark the beginning of the
  624.   configuration data area for FBROWSE; FBrowserCfgEnd marks the end of the
  625.   data area. In between them is FBrowserKeySet, the command table used by
  626.   FBrowserCommands. FBrowserKeyMax is the last valid index into the table.
  627.  
  628.     otFBrowser         = 999;
  629.     veFBrowser         = 0;
  630.     otVBrowser         = 998;
  631.     veVBrowser         = 0;
  632.     ptFBrowserCommands = 999;
  633.     ptNullFilterFunc   = 998;
  634.     ptNullRefreshFunc  = 997;
  635.  
  636.   Object type, version, and pointer type codes used internally when storing an
  637.   FBrowser in a stream.
  638.  
  639.     ucFBrowser         = 99;
  640.  
  641.   FBROWSE's unit code, which is passed to the help routine (if any) when the
  642.   ccHelp command is issued.
  643.  
  644. Types
  645.  
  646.     BuildItemProc =
  647.       procedure (Row : Byte; var DatS; Len : Word; RecNum : LongInt;
  648.                  Key : IsamKeyStr; var S : string; FBP : FBrowserPtr);
  649.  
  650.   A user-written routine that builds the string(s) corresponding to a given
  651.   item (record). See the entry for SetBuildItemProc for more information.
  652.  
  653.     FBrowserPtr = ^FBrowser;
  654.     FBrowser =
  655.       object(CommandWindow)
  656.         ...
  657.       end;
  658.  
  659.   A window-based object used for browsing through datafiles containing
  660.   fixed-length records in indexed order.
  661.  
  662.     FilterFunc =
  663.       function (RecNum : LongInt; Key : IsamKeyStr;
  664.                 FBP : FBrowserPtr) : Boolean;
  665.  
  666.   A user-written routine that is called to determine whether or not a given
  667.   record should be displayed.
  668.  
  669.     RefreshFunc = function (FBP : FBrowserPtr) : Boolean;
  670.  
  671.   A user-written routine that is called just before asking for the next
  672.   command.
  673.  
  674.     SpecialTaskProc =
  675.       procedure (RecNum : LongInt; Key : IsamKeyStr; FBP : FBrowserPtr);
  676.  
  677.   A user-written routine that is called when one of the special task
  678.   commands (ccTask0..ccTask19) is issued. A pre-move procedure is also of this
  679.   type.
  680.  
  681.     UpdateProc = procedure (FBP : FBrowserPtr);
  682.  
  683.   A user-written routine that is called each time the browser's window is
  684.   redrawn or scrolled.
  685.  
  686. Variables
  687.  
  688.     {$IFDEF UseDrag}
  689.     FBrowserCommands : DragProcessor;
  690.     {$ELSE}
  691.     FBrowserCommands : CommandProcessor;
  692.     {$ENDIF}
  693.  
  694.   The default CommandProcessor for an FBrowser. UseDrag is a conditional
  695.   define in OPDEFINE.INC (OPRO version 1.03 or higher).
  696.  
  697.  
  698. ------- FBrowser -----------------------------------------------------------
  699.  
  700.  
  701. This section describes each of the documented methods implemented in the
  702. FBrowser object. Note that in many cases the "See Also" section of an entry
  703. makes reference to a method implemented by one of FBrowser's parents, such as
  704. CommandWindow.Done. Documentation for these methods may be found in the Object
  705. Professional manual.
  706.  
  707.  
  708. Declaration
  709.   procedure BuildOneRow(Row : Byte; var DatS; Len : Word; RecNum : LongInt;
  710.                         Key : IsamKeyStr; var S : string); virtual;
  711. Purpose
  712.   Convert specified row of specified item to a string.
  713. Description
  714.   You may override this virtual method in lieu of calling SetBuildItemProc.
  715.   This method is called by BuildOneItem once for each row in the item, and
  716.   (by default) it in turn calls the BuildItem routine specified in the call to
  717.   SetBuildItemProc.
  718. See Also
  719.   BuildOneItem  SetBuildItemProc
  720.  
  721.  
  722. Declaration
  723.   procedure BuildOneItem(Item : Byte; Locked : Boolean); virtual;
  724. Purpose
  725.   Convert specified item to a string.
  726. Description
  727.   You may override this virtual method in lieu of calling SetBuildItemProc.
  728.  
  729.   If Locked is True, the record corresponding to Item does not need to be
  730.   read. BuildOneItem should skip that step and behave as it would if an
  731.   attempt to read the record had failed due to a lock error.
  732. See Also
  733.   BuildOneRow  SetBuildItemProc
  734.  
  735.  
  736. Declaration
  737.   procedure CharHook; virtual;
  738. Purpose
  739.   Called each time a regular character is entered by the user.
  740. Description
  741.   This method, which is called each time that a regular character is entered
  742.   by the user (i.e., the ccChar command is generated), does nothing by
  743.   default. It exists only to provide a hook that allows derived object types
  744.   to provide incremental searching capabilities of the type found in
  745.   PickLists.
  746.  
  747.   The keys to implementing this kind of functionality are the
  748.   GetCurrentKeyAndRef and SetCurrentRecord methods. GetCurrentKeyAndRef
  749.   returns the key and reference number for the currently selected item, which
  750.   together provide a starting point for a search operation. Once the search
  751.   engine has found the record to be highlighted, SetCurrentRecord may be
  752.   called to move the highlight bar.
  753. See Also
  754.   GetCurrentKeyAndRef  SetCurrentRecord
  755.  
  756.  
  757. Declaration
  758.   procedure CursorLeft; virtual;
  759. Purpose
  760.   Called to process the ccLeft command.
  761. Description
  762.   This method provides a hook that allows derived object types to scroll
  763.   the display horizontally in variably-sized increments when the ccLeft
  764.   command is issued. It thus allows you, for example, to alter the behavior of
  765.   the browser so that ccLeft scrolls the display left by one field rather than
  766.   a fixed number of columns (usually one). Such a method would look something
  767.   like this in outline:
  768.  
  769.     procedure MyEntryScreen.CursorLeft;
  770.     var
  771.       NewColumn : Word;
  772.     begin
  773.       {calculate value for NewColumn based on GetCurrentCol}
  774.       fbScrollHoriz(NewColumn-GetCurrentCol);
  775.     end;
  776.  
  777.   fbScrollHoriz is a method that scrolls the display horizontally in either
  778.   direction (negative values scroll the display to the left, positive values
  779.   scroll it to the right).
  780. See Also
  781.   CursorRight  GetCurrentCol
  782.  
  783.  
  784. Declaration
  785.   procedure CursorRight; virtual;
  786. Purpose
  787.   Called to process the ccRight command.
  788. Description
  789.   This method provides a hook that allows derived object types to scroll
  790.   the display horizontally in variably-sized increments when the ccRight
  791.   command is issued. It thus allows you, for example, to alter the behavior of
  792.   the browser so that ccRight scrolls the display right by one field rather
  793.   than by a fixed number of columns (usually one). Such a method would look
  794.   something like this in outline:
  795.  
  796.     procedure MyEntryScreen.CursorRight;
  797.     var
  798.       NewColumn : Word;
  799.     begin
  800.       {calculate value for NewColumn based on GetCurrentCol}
  801.       fbScrollHoriz(NewColumn-GetCurrentCol);
  802.     end;
  803.  
  804.   fbScrollHoriz is a method that scrolls the display horizontally in either
  805.   direction (negative values scroll the display to the left, positive values
  806.   scroll it to the right).
  807. See Also
  808.   CursorLeft  GetCurrentCol
  809.  
  810.  
  811. Declaration
  812.   destructor Done; virtual;
  813. Purpose
  814.   Deallocate item records.
  815. Description
  816.   This destructor disposes of all memory allocated for item records and then
  817.   calls the parent's destructor to deallocate memory used for window buffers,
  818.   shadows, etc.
  819. See Also
  820.   CommandWindow.Done  Init  InitCustom
  821.  
  822.  
  823. Declaration
  824.   procedure DrawItem(Item : Byte; Highlight : Boolean); virtual;
  825. Purpose
  826.   Draw the specified (relative) Item of the browse window.
  827. Description
  828.   This method should not be called directly. It is documented only because it
  829.   will sometimes be desirable to override it. For example, if you wanted to
  830.   display different sections of a given item in different video attributes,
  831.   you could do so by overriding this method. The best way to approach the task
  832.   would be to make a copy of the source code for FBrowser.DrawItem and modify
  833.   it to do what you want.
  834.  
  835.  
  836. Declaration
  837.   function fbOptionsAreOn(OptionFlags : LongInt) : Boolean;
  838. Purpose
  839.   Return True if all specified options are on.
  840. Description
  841.   This method returns True if all of the specified options are currently
  842.   selected.
  843. Example
  844.     if FB.fbOptionsAreOn(fbScrollByPage) then
  845.       FB.fbOptionsOff(fbScrollByPage)
  846.     else
  847.       FB.fbOptionsOn(fbScrollByPage);
  848.  
  849.   Toggle the scroll-by-page option.
  850. See Also
  851.   fbOptionsOn  fbOptionsOff
  852.  
  853.  
  854. Declaration
  855.   procedure fbOptionsOff(OptionFlags : LongInt);
  856. Purpose
  857.   Deactivate multiple options.
  858. Description
  859.   This method deactivates the specified option(s), excluding those
  860.   designated as BadFBrowserOptions (see the Constants section, above).
  861. See Also
  862.   fbOptionsAreOn  fbOptionsOn
  863.  
  864.  
  865. Declaration
  866.   procedure fbOptionsOn(OptionFlags : LongInt);
  867. Purpose
  868.   Activate multiple options.
  869. Description
  870.   This method activates the specified option(s), excluding those designated
  871.   as BadFBrowserOptions (see the Constants section, above).
  872. See Also
  873.   fbOptionsAreOn  fbOptionsOff
  874.  
  875.  
  876. Declaration
  877.   function GetCurrentCol : Word;
  878. Purpose
  879.   Get column currently displayed at left edge of window.
  880. Description
  881.   Returns the number of the column currently displayed at the left edge of
  882.   the window. This information is generally useful only in user-written
  883.   screen update routines. Note that, if the window does not scroll
  884.   horizontally, GetCurrentCol will always return 1.
  885. Example
  886.   See the UpdateScreen routine in FBDEMO.PAS.
  887. See Also
  888.   GetCurrentItem  GetFirstCol  SetScreenUpdateProc
  889.  
  890.  
  891. Declaration
  892.   function GetFirstCol : Word;
  893. Purpose
  894.   Get first column of data to be loaded into memory.
  895. Description
  896.   This function should be called by build item routines in cases where the
  897.   maximum number of columns per row is greater than 255. It indicates the
  898.   first column of data that should be returned. See the section on "Rows
  899.   Longer than 255 Characters," above, for details.
  900. See Also
  901.   GetCurrentCol  SetBuildItemProc
  902.  
  903.  
  904. Declaration
  905.   function GetCurrentItem : Byte;
  906. Purpose
  907.   Get number of currently highlighted item.
  908. Description
  909.   Returns a number indicating which item in the window is currently
  910.   highlighted. The item displayed at the top of the window is item 1, the item
  911.   below it is item 2, and so on.
  912. See Also
  913.   GetCurrentCol  GetItemString
  914.  
  915.  
  916. Declaration
  917.   procedure GetCurrentKeyAndRef(var Key : IsamKeyStr; var Ref : LongInt);
  918. Purpose
  919.   Retrieve current key and reference number.
  920. Description
  921.   Returns the key and reference number for the currently highlighted item.
  922. See Also
  923.   GetCurrentRecord
  924.  
  925.  
  926. Declaration
  927.   procedure GetCurrentRecord(var DatS; var DatLen : Word);
  928. Purpose
  929.   Retrieve current record.
  930. Description
  931.   Reads the current record into the variable passed as the DatS parameter.
  932.   DatLen is the length of the record read in, information that is important
  933.   only for variable-length Fileblocks.
  934.  
  935.   IMPORTANT: Be sure to check IsamOK after calling this method to determine
  936.   whether or not the record was read successfully.
  937. Example
  938.   See FBDEMO.PAS.
  939. See Also
  940.   GetCurrentKeyAndRef  GetRecord  SetCurrentRecord
  941.  
  942.  
  943. Declaration
  944.   function GetFileBlockPtr : IsamFileBlockPtr;
  945. Purpose
  946.   Get pointer to associated Fileblock.
  947. Description
  948.   Returns a pointer to the Fileblock being browsed, the same pointer that
  949.   was passed to the Init constructor.
  950. See Also
  951.   InitCustom
  952.  
  953.  
  954. Declaration
  955.   function GetItemString(Item, Row : Byte) : string; virtual;
  956. Purpose
  957.   Get string corresponding to specified Row of specified Item.
  958. Description
  959.   This function may be used to access the string(s) displayed by the browser
  960.   for a given item.
  961. Example
  962.     FB.GetItemString(FB.GetCurrentItem, 1)
  963.  
  964.   Returns string corresponding to row 1 of the currently selected item.
  965. See Also
  966.   GetCurrentItem
  967.  
  968.  
  969. Declaration
  970.   function GetKeyNumber : Integer;
  971. Purpose
  972.   Get current index key number.
  973. Description
  974.   This function indicates which set of index keys is being used to determine
  975.   the order in which records are displayed.
  976. Example
  977.     if FB.GetKeyNumber = 1 then
  978.       FB.SetKeyNumber(2)
  979.     else
  980.       FB.SetKeyNumber(1);
  981.  
  982.   Toggle between key numbers 1 and 2.
  983. See Also
  984.   SetKeyNumber
  985.  
  986.  
  987. Declaration
  988.   procedure GetRecord(Ref : LongInt; var DatS; var Len : Word); virtual;
  989. Purpose
  990.   Low-level routine to read a specific record.
  991. Description
  992.   This method is intended primarily for internal use, but you may use it if
  993.   you wish (see the ValidatePerson routine--a filter function--in FBDEMO.PAS).
  994.   It is documented primarily because it will sometimes be desirable to
  995.   override it. The VBrowser object overrides it, for example, in order to
  996.   provide support for variable-length records. You may wish to override it in
  997.   order to implement a record caching scheme, for example.
  998.  
  999.   Note that GetRecord does not retry if the attempt to read the record fails
  1000.   due to a lock error.
  1001. See Also
  1002.   GetCurrentRecord
  1003.  
  1004.  
  1005. Declaration
  1006.   constructor Init(X1, Y1, X2, Y2 : Byte;
  1007.                    IFBPtr : IsamFileBlockPtr;
  1008.                    KeyNum : Integer;
  1009.                    var DatS;
  1010.                    MaxRows, RowsPerItem : Byte;
  1011.                    MaxCols : Word);
  1012. Purpose
  1013.   Initialize an FBrowser with default window options.
  1014. Description
  1015.   This constructor instantiates an FBrowser using the default window options
  1016.   (DefWindowOptions) and the default color set (DefaultColorSet). See
  1017.   InitCustom for further details.
  1018. Example
  1019.   See the FBSIMPLE example program, above.
  1020. See Also
  1021.   InitCustom
  1022.  
  1023.  
  1024. Declaration
  1025.   constructor InitCustom(X1, Y1, X2, Y2 : Byte;
  1026.                          var Colors : ColorSet;
  1027.                          Options : LongInt;
  1028.                          IFBPtr : IsamFileBlockPtr;
  1029.                          KeyNum : Integer;
  1030.                          var DatS;
  1031.                          MaxRows, RowsPerItem : Byte;
  1032.                          MaxCols : Word);
  1033. Purpose
  1034.   Initialize an FBrowser with custom window options.
  1035. Description
  1036.   InitCustom instantiates an FBrowser using the specified window Options and
  1037.   Colors. X1, Y1, X2, and Y2 are the coordinates for the interior of the
  1038.   window, where the contents of the data file are displayed.
  1039.  
  1040.   The IFBPtr parameter must be a pointer to an open Fileblock. Note that
  1041.   InitCustom has no means of determining whether or not this requirement has
  1042.   been met, so no error will be generated if it isn't.
  1043.  
  1044.   KeyNum indicates which set of index keys to use for ordering the records to
  1045.   be displayed. Note that the Fileblock must have at least one set of keys. If
  1046.   it doesn't, InitCustom will fail with InitStatus set to epFatal+ecNoIndex.
  1047.  
  1048.   DatS should name a record variable of the type stored in the Fileblock.
  1049.   Normally it should be a global variable (stored in the data segment) or a
  1050.   variable allocated on the heap, but it may be a local variable (stored on
  1051.   the stack) if the FBrowser object is used only within the scope of the same
  1052.   procedure.
  1053.  
  1054.   MaxRows specifies the maximum number of rows to be displayed in the browse
  1055.   window. In most cases, MaxRows should be equal to the height of the window
  1056.   (Y2-Y1+1), and if that's what you want you can simply pass 0. If the window
  1057.   is resizeable, however, you may want to specify a larger value.
  1058.   RowsPerItem indicates how many rows of information are required to display a
  1059.   given item; normally this will be 1. The maximum number of items that can be
  1060.   displayed at one time may be calculated as MaxRows div RowsPerItem. MaxCols
  1061.   specifies the maximum number of columns to be displayed on a given row. If
  1062.   you pass 0, InitCustom will set the maximum columns equal to the width of
  1063.   the window. Note that the text in the window will not scroll horizontally if
  1064.   MaxCols is less than or equal to the width.
  1065.  
  1066.   InitCustom will try to allocate a variably-sized array containing
  1067.   information about the items it is displaying; the actual size and contents
  1068.   of the array depend on the values passed for MaxRows, RowsPerItem, and
  1069.   MaxCols. InitCustom will fail if it is unable to allocate this array. It
  1070.   will also fail if RowsPerItem is greater than either Self.Height or MaxRows
  1071.   (InitStatus = epFatal+ecWinTooSmall). The most likely cause of failure is
  1072.   insufficient memory. The precise cause may be determined by examining
  1073.   InitStatus.
  1074.  
  1075.   Two sets of attributes in the specified ColorSet have special relevance for
  1076.   window objects of type FBrowser. TextColor/TextMono determine the attribute
  1077.   used for unselected items, and SelItemColor/SelItemMono determine the
  1078.   attribute used for selected items. After the object has been instantiated,
  1079.   these attributes may be changed by calling the SetNormAttr and SetSelectAttr
  1080.   methods, respectively.
  1081.  
  1082.   Note that the browser will remain in a semi-uninitialized state until Draw
  1083.   or Process is called. That is, you should not call any of the following
  1084.   methods in the interim: GetCurrentItem, GetCurrentKeyAndRef,
  1085.   GetCurrentRecord, or GetItemString. Doing so is considered a fundamental
  1086.   programming error, and no error will be generated if you commit it.
  1087. Example
  1088.     if not InitCustom(2, 2, ScreenWidth-1, ScreenHeight-1,
  1089.                       DefaultColorSet, DefWindowOptions or wBordered,
  1090.                       MyIFBPtr, 1, MyRecordBuffer,
  1091.                       0, 1, 0) then begin
  1092.       WriteLn('Failed to init FBrowser. Status = ', InitStatus);
  1093.       Halt;
  1094.     end;
  1095.  
  1096.   Instantiates a bordered, full-screen file browser with the default color
  1097.   set. MyIFBPtr is a Fileblock that has already been opened.
  1098.   MyRecordBuffer is a record variable of the size and type stored in the
  1099.   Fileblock. The values for MaxRows and MaxCols will be calculated based on
  1100.   the height and width of the window, respectively.
  1101. See Also
  1102.   CommandWindow.InitCustom  Init
  1103.  
  1104.  
  1105. Declaration
  1106.   function IsFilteringEnabled : Boolean; virtual;
  1107. Purpose
  1108.   Return True if filtering is enabled.
  1109. Description
  1110.   This function returns True if record filtering has been "enabled" by
  1111.   using SetFilterFunc to specify a filter function other than
  1112.   NullFilterFunc.
  1113. Example
  1114.     if FB.IsFilteringEnabled
  1115.       FB.SetFilterFunc(NullFilterFunc)
  1116.     else
  1117.       FB.SetFilterFunc(MyFilterFunc);
  1118.  
  1119.   Toggle record filtering.
  1120. See Also
  1121.   NullFilterFunc  RecordFilter  SetFilterFunc
  1122.  
  1123.  
  1124. Declaration
  1125.   constructor Load(var S : IdStream);
  1126. Purpose
  1127.   Load a file browser from a stream.
  1128. Description
  1129.   S is a properly initialized stream object (a stream file opened for reading,
  1130.   for example). Note that S can be any descendant of the IdStream type, which
  1131.   includes DosIdStream, BufIdStream, and MemIdStream. Load reads the next
  1132.   sequence of bytes from the stream S. These bytes must have been written by a
  1133.   previous call to FBrowser.Store.
  1134.  
  1135.   The stream registration procedure for an FBrowser is FBrowserStream. The
  1136.   stream registration procedure for a VBrowser is VBrowserStream.
  1137.  
  1138.   For additional information, see the discussion of Streams in the
  1139.   Miscellaneous Issues section, above.
  1140. Example
  1141.   See the InitBrowser routine in FBDEMO.PAS.
  1142. See Also
  1143.   Store
  1144.  
  1145.  
  1146. Declaration
  1147.   function NeedRefresh : Boolean; virtual;
  1148. Purpose
  1149.   Do we need to refresh the display?
  1150. Description
  1151.   You may override this virtual method in lieu of calling SetRefreshFunc.
  1152.   NeedRefresh is called by FBrowser's ProcessSelf method just after it calls
  1153.   the PreMove method. If NeedRefresh returns True, the ccPlus command is
  1154.   executed; otherwise, GetNextCommand is called to get the next command from
  1155.   the user.
  1156. See Also
  1157.   SetRefreshFunc
  1158.  
  1159.  
  1160. Declaration
  1161.   procedure PreMove; virtual;
  1162. Purpose
  1163.   Called just prior to getting each keyboard command.
  1164. Description
  1165.   You may override this virtual method in lieu of calling SetPreMoveProc.
  1166.   PreMove is called by FBrowser's ProcessSelf method just before it calls
  1167.   NeedRefresh.
  1168. See Also
  1169.   SetPreMoveProc
  1170.  
  1171.  
  1172. Declaration
  1173.   procedure ProcessSelf; virtual;
  1174. Purpose
  1175.   Process browse commands.
  1176. Description
  1177.   The FBrowser's ProcessSelf method follows the general model described in the
  1178.   Object Professional manual under CommandWindow.Process.
  1179. See Also
  1180.   CommandWindow.Process
  1181.  
  1182.  
  1183. Declaration
  1184.   function RecordFilter(RecNum : LongInt; Key : IsamKeyStr) : Boolean; virtual;
  1185. Purpose
  1186.   Return True if this record should be displayed.
  1187. Description
  1188.   You may override this virtual method in lieu of calling SetFilterFunc. Note
  1189.   that, if you did so, you should also override the IsFilteringEnabled method.
  1190. See Also
  1191.   SetFilterFunc
  1192.  
  1193.  
  1194. Declaration
  1195.   procedure ScreenUpdate; virtual;
  1196. Purpose
  1197.   Called on each screen update; when current item/column changes.
  1198. Description
  1199.   You may override this virtual method in lieu of calling SetScreenUpdateProc.
  1200. See Also
  1201.   SetScreenUpdateProc
  1202.  
  1203.  
  1204. Declaration
  1205.   procedure SetBuildItemProc(BIF : BuildItemProc);
  1206. Purpose
  1207.   Set procedure to build an item.
  1208. Description
  1209.   This is used to specify a user-supplied procedure that will take a record
  1210.   read in from the data file and return the formatted string to be displayed
  1211.   in the window.
  1212.  
  1213.   VERY IMPORTANT: When you use an FBrowser object, you MUST either call this
  1214.   method or override the BuildOneItem method.
  1215.  
  1216.   A build item procedure must be of the following form:
  1217.  
  1218.     {$F+}
  1219.     procedure BuildItem(Row : Byte; var DatS; Len : Word;
  1220.                         RecNum : LongInt; Key : IsamKeyStr;
  1221.                         var S : string; FBP : FBrowserPtr);
  1222.     begin
  1223.       S := ????;
  1224.     end;
  1225.  
  1226.   The Row parameter is meaningful only if each item occupies more than one
  1227.   row; if so, Row indicates which row (1..n) of the item needs to be built.
  1228.   DatS is the record to be converted to a string. Len is its length. RecNum is
  1229.   its reference number. Key is the corresponding key in the index file. S is
  1230.   the string to be displayed. And FBP is the address of the FBrowser making
  1231.   the call.
  1232.  
  1233.   If the maximum number of columns per row is greater than 255, GetFirstCol
  1234.   should be called to determine which columns of data are needed. See the
  1235.   section on "Rows Longer than 255 Characters," above, for details.
  1236.  
  1237.   IMPORTANT: If the RecNum parameter is -1, the record in question could not
  1238.   be read due to a file or record lock. In this case, the DatS and Len
  1239.   parameters should be ignored, and the string returned should give the user
  1240.   some indication that the record couldn't be read. (See the BuildRow routine
  1241.   in FBDEMO.PAS for an example.)
  1242.  
  1243.   Note: If your build item procedure needs only the information in the Key
  1244.   parameter in order to build the row, you can improve performance markedly by
  1245.   setting the fbBuildOnKey option.
  1246. Example
  1247.   See the BuildRow routine in FBDEMO.PAS.
  1248. See Also
  1249.   BuildOneItem  BuildOneRow  GetFirstCol
  1250.  
  1251.  
  1252. Declaration
  1253.   procedure SetCurrentRecord(Key : IsamKeyStr; Ref : LongInt);
  1254. Purpose
  1255.   Set the current record.
  1256. Description
  1257.   This method allows you to move the highlight bar from one record to another.
  1258.   Normally Key and Ref should identify a record that is known to exist, but it
  1259.   may also be used to move the highlight to an approximate location (see the
  1260.   first example below). Note that, if the browser is the current window, the
  1261.   screen will be updated immediately.
  1262.  
  1263.   If it isn't current, the change will not take effect until Draw or Process
  1264.   is called, and the browser will be in a semi-uninitialized state until then.
  1265.   That is, you should not call any of the following methods in the interim:
  1266.   GetCurrentItem, GetCurrentKeyAndRef, GetCurrentRecord, or GetItemString.
  1267.   Doing so is considered a fundamental programming error, and no error will be
  1268.   generated if you commit it.
  1269. Examples
  1270.     SetCurrentRecord('', 1);
  1271.  
  1272.   Move highlight to the first record in the file. This is the default
  1273.   situation, when an FBrowser is instantiated.
  1274.  
  1275.     SetCurrentRecord(MyKey, MyRef);
  1276.  
  1277.   Move highlight to the record with a key of MyKey and a reference number of
  1278.   MyRef.
  1279. See Also
  1280.   CharHook  GetCurrentRecord
  1281.  
  1282.  
  1283. Declaration
  1284.   procedure SetFilterFunc(FF : FilterFunc);
  1285. Purpose
  1286.   Set record filtering function.
  1287. Description
  1288.   This method allows you to specify a function that can selectively filter out
  1289.   records that you don't want displayed. For example, if you wanted to display
  1290.   in alphabetical order the names of all people in the database who lived in a
  1291.   particular state, and the database was indexed by name, you could simply
  1292.   write a filter function that read in the record under consideration and
  1293.   returned True if the state was a match.
  1294.  
  1295.   A filter function must be of the following form:
  1296.  
  1297.     {$F+}
  1298.     function MyFilter(RecNum : LongInt; Key : IsamKeyStr;
  1299.                       FBP : FBrowserPtr) : Boolean;
  1300.     begin
  1301.     end;
  1302.  
  1303.   RecNum is the reference number for the currently selected item. Key is the
  1304.   corresponding index key. FBP is the address of the FBrowser making the call.
  1305.   The function should return True to display the record, or False to skip it.
  1306.  
  1307.   Note: Be forewarned that filtering a database in this "brute force" fashion
  1308.   can degrade the browser's performance markedly, particularly when the
  1309.   database is large. Where possible, filtering should instead be performed by
  1310.   specifying a range of index keys or by building a temporary index.
  1311. Example
  1312.   See the ValidatePerson function in FBDEMO.PAS.
  1313. See Also
  1314.   IsFilteringEnabled  NullFilterFunc  RecordFilter  SetKeyRange
  1315.  
  1316.  
  1317. Declaration
  1318.   {$IFDEF UseScrollBars}
  1319.   procedure SetHorizScrollBarDelta(Delta : Byte);
  1320. Purpose
  1321.   Set columns to jump when scrolling horizontally (via a scroll bar).
  1322. Description
  1323.   This method is similar to SetHorizScrollDelta. It may be used to specify the
  1324.   number of columns that the display is scrolled when the mouse is clicked on
  1325.   the left or right arrows of a horizontal scroll bar.
  1326. See Also
  1327.   SetHorizScrollDelta
  1328.  
  1329.  
  1330. Declaration
  1331.   procedure SetHorizScrollDelta(Delta : Byte);
  1332. Purpose
  1333.   Set columns to jump when scrolling horizontally.
  1334. Description
  1335.   This method allows you to specify how many columns the display should "jump"
  1336.   when the window has to be scrolled horizontally (when <Left> or <Right> is
  1337.   pressed). The default setting is 1. Note that if Delta is greater than
  1338.   Self.Width (i.e., the width of the interior portion of the window), the
  1339.   display will be scrolled Self.Width columns at a time.
  1340. See Also
  1341.   SetHorizScrollBarDelta  SetVertScrollDelta
  1342.  
  1343.  
  1344. Declaration
  1345.   procedure SetKeyNumber(KeyNum : Integer);
  1346. Purpose
  1347.   Switch index keys.
  1348. Description
  1349.   This method allows you to switch index keys after the browser has been
  1350.   initialized. It should not be called while Process is active (from within
  1351.   a special task procedure, for example); if it is, SetKeyNumber will do
  1352.   nothing. Note that SetKeyNumber also calls SetKeyRange to cancel the current
  1353.   range settings.
  1354. See Also
  1355.   GetKeyNumber  SetKeyRange
  1356.  
  1357.  
  1358. Declaration
  1359.   procedure SetKeyRange(LowKey, HighKey : IsamKeyStr);
  1360. Purpose
  1361.   Set subrange of valid keys.
  1362. Description
  1363.   This method allows you to specify a range of records to be displayed,
  1364.   based on index keys. Note that it does nothing if called while Process is
  1365.   active (e.g., if called from a special task procedure).
  1366. Example
  1367.     FB.SetKeyRange('A'#0, 'A'#255);
  1368.  
  1369.   Display only those records whose keys start with 'A'.
  1370. See Also
  1371.   SetKeyNumber
  1372.  
  1373.  
  1374. Declaration
  1375.   procedure SetNormAttr(Color, Mono : Byte);
  1376. Purpose
  1377.   Set attribute for unselected items.
  1378. Description
  1379.   This method allows you to set the attribute used to display unselected
  1380.   items.
  1381. See Also
  1382.   SetSelectAttr
  1383.  
  1384.  
  1385. Declaration
  1386.   procedure SetPreMoveProc(PMP : SpecialTaskProc);
  1387. Purpose
  1388.   Set user-defined procedure to call before each command.
  1389. Description
  1390.   This method allows you to specify a procedure that is to be called just
  1391.   before the Process method asks the browser's CommandProcessor for the next
  1392.   command. This hook may be used, for example, to display additional
  1393.   information about the currently selected item, or to update a second browser
  1394.   whose Fileblock is related to the first.
  1395.  
  1396.   A pre-move procedure must be of the following form:
  1397.  
  1398.     {$F+}
  1399.     procedure MyPreMove(RecNum : LongInt; Key : IsamKeyStr;
  1400.                         FBP : FBrowserPtr);
  1401.     begin
  1402.     end;
  1403.  
  1404.   RecNum is the reference number for the currently selected item. Key is the
  1405.   corresponding index key. FBP is the address of the FBrowser making the call.
  1406. See Also
  1407.   PreMove
  1408.  
  1409.  
  1410. Declaration
  1411.   procedure SetRefreshFunc(RF : RefreshFunc);
  1412. Purpose
  1413.   Set routine called to determine if screen refresh is needed.
  1414. Description
  1415.   This method allows you to specify a function that can request a complete
  1416.   screen update. This facility is useful only in multi-user applications,
  1417.   where other workstations can alter the contents of the database, potentially
  1418.   affecting the accuracy of the data displayed on the current workstation.
  1419.   Normally changes made by other workstations are reflected only when the user
  1420.   issues a command (such as <PgUp>) that causes the browser to build a new
  1421.   page of data. The refresh function hook makes it possible for the browser's
  1422.   display to be updated more or less continuously on an as-needed basis.
  1423.  
  1424.   The FBROWSE unit contains two ready-made refresh functions that you may
  1425.   activate if you wish, RefreshAtEachCommand and RefreshPeriodically, both of
  1426.   which rely on the PageStackValid function in the FILER unit. Alternative
  1427.   refresh functions might be written using, for example, IPX services or
  1428.   Novell's semaphore services. The latter approach is demonstrated in
  1429.   FBDEMO.PAS, which uses the routines in NETSEMA.PAS and OOPSEMA.PAS when
  1430.   compiled for Novell. (To see how the semaphore services were used in FBDEMO,
  1431.   load FBDEMO.PAS into an editor and search for the string '{$IFDEF Novell}'.)
  1432.  
  1433.   A refresh function must be of the following form:
  1434.  
  1435.     {$F+}
  1436.     function MyRefreshFunc(FBP : FBrowserPtr) : Boolean;
  1437.     begin
  1438.     end;
  1439.  
  1440.   FBP is the address of the FBrowser making the call. The function should
  1441.   return True if the display needs to be rebuilt and redrawn ("refreshed").
  1442. Example
  1443.     SetRefreshFunc(RefreshPeriodically);
  1444.     RefreshPeriod := 18*3;
  1445.  
  1446.   Enable the RefreshPeriodically function and set the interval between
  1447.   checks to 3 seconds.
  1448. See Also
  1449.   NeedRefresh  NullRefreshFunc  RefreshAtEachCommand  RefreshPeriodically
  1450.  
  1451.  
  1452. Declaration
  1453.   procedure SetRetries(Retries : Integer);
  1454. Purpose
  1455.   Set number of times to retry on I/O operations.
  1456. Description
  1457.   This method allows you to specify the number of times that the browser
  1458.   should retry an I/O operation in the event of a lock error. The default
  1459.   setting is 50 (DefRetriesOnLock).
  1460.  
  1461.  
  1462. Declaration
  1463.   procedure SetScreenUpdateProc(SUP : UpdateProc);
  1464. Purpose
  1465.   Set user-defined procedure to call on each screen update.
  1466. Description
  1467.   This method allows you to specify a routine that is to be called each time
  1468.   that the browser's window is redrawn or scrolled. It is especially useful in
  1469.   cases where the window has a row of column headers that need to scroll
  1470.   horizontally in unison with the text in the window proper. (See the
  1471.   UpdateScreen routine in FBDEMO.PAS for an example of such a case.)
  1472.  
  1473.   A screen update procedure must be of the following form:
  1474.  
  1475.     {$F+}
  1476.     procedure MyScreenUpdate(FBP : FBrowserPtr);
  1477.     begin
  1478.     end;
  1479.  
  1480.   FBP is the address of the FBrowser making the call.
  1481. Example
  1482.   See the UpdateScreen routine in FBDEMO.PAS.
  1483. See Also
  1484.   ScreenUpdate
  1485.  
  1486.  
  1487. Declaration
  1488.   procedure SetSelectAttr(Color, Mono : Byte);
  1489. Purpose
  1490.   Set attribute for selected items.
  1491. Description
  1492.   This method allows you to set the attribute used to highlight the
  1493.   currently selected item.
  1494. See Also
  1495.   SetNormAttr
  1496.  
  1497.  
  1498. Declaration
  1499.   procedure SetSpecialTaskProc(STP : SpecialTaskProc);
  1500. Purpose
  1501.   Set user-defined special task hook.
  1502. Description
  1503.   This method allows you to specify a routine that is to be called whenever a
  1504.   command in the range ccTask0..ccTask19 is issued. The hook thus provides a
  1505.   convenient means of adding user-defined commands that can be executed
  1506.   without exiting from Process. It is especially useful for implementing
  1507.   commands that simply toggle configuration options on or off.
  1508.  
  1509.   Note that a special task procedure may force another command (ccUp, ccHome,
  1510.   etc.) to be executed by calling the SetLastCommand method. If no other
  1511.   command needs to be executed, the special task procedure should call
  1512.   SetLastCommand with a parameter of ccNone.
  1513.  
  1514.   A special task procedure must be of the following form:
  1515.  
  1516.     {$F+}
  1517.     procedure MySpecialTask(RecNum : LongInt; Key : IsamKeyStr;
  1518.                             FBP : FBrowserPtr);
  1519.     begin
  1520.       { FBP^.SetLastCommand(ccNone); }
  1521.     end;
  1522.  
  1523.   RecNum is the reference number for the currently selected item. Key is the
  1524.   corresponding index key. FBP is the address of the FBrowser making the call.
  1525. See Also
  1526.   SpecialTask
  1527.  
  1528.  
  1529. Declaration
  1530.   procedure SetVertScrollDelta(Delta : Byte);
  1531. Purpose
  1532.   Set rows (items) to jump when scrolling vertically.
  1533. Description
  1534.   This method allows you to specify how many items the display should "jump"
  1535.   when the window has to be scrolled vertically (when <Up> or <Down> is
  1536.   pressed). The default setting is 1. Note that if Delta is greater than NI,
  1537.   where NI is the number of items in the window, the display will be scrolled
  1538.   NI items at a time, just as it would be if the fbScrollByPage option were
  1539.   set.
  1540. See Also
  1541.   SetHorizScrollDelta
  1542.  
  1543.  
  1544. Declaration
  1545.   procedure SpecialTask; virtual;
  1546. Purpose
  1547.   Special task hook.
  1548. Description
  1549.   You may override this virtual method in lieu of calling SetSpecialTaskProc.
  1550. See Also
  1551.   SetSpecialTaskProc
  1552.  
  1553.  
  1554. Declaration
  1555.   procedure Store(var S : IdStream);
  1556. Purpose
  1557.   Store a file browser in a stream.
  1558. Description
  1559.   S is a properly initialized stream object (a stream file opened for writing,
  1560.   usually). Note that S can be any descendant of the IdStream type, which
  1561.   includes DosIdStream, BufIdStream, and MemIdStream (although you typically
  1562.   wouldn't write to a MemIdStream).
  1563.  
  1564.   Store writes an image of the FBrowser's data to the stream S. (See the
  1565.   discussion of Streams in the Miscellaneous Issues section, above.)
  1566.  
  1567.   The stream registration procedure for an FBrowser is FBrowserStream. The
  1568.   stream registration procedure for a VBrowser is VBrowserStream.
  1569. Example
  1570.   See the InitBrowser routine in FBDEMO.PAS.
  1571. See Also
  1572.   Load
  1573.  
  1574.  
  1575. ------- VBrowser -----------------------------------------------------------
  1576.  
  1577.  
  1578. The FBrowser object works only with Fileblocks containing fixed-length
  1579. records. In order to browse a file containing variable-length records, you
  1580. must use the VBrowser object instead:
  1581.  
  1582. Types
  1583.  
  1584.   VBrowserPtr = ^VBrowser;
  1585.   VBrowser =
  1586.     object(FBrowser)
  1587.     end;
  1588.  
  1589.   A window-based object used for browsing through datafiles containing
  1590.   variable-length records in indexed order.
  1591.  
  1592.  
  1593. Declaration
  1594.   procedure GetRecord(Ref : LongInt; var Len : Word); virtual;
  1595. Purpose
  1596.   Low-level routine to read a specific record.
  1597. Description
  1598.   VBrowser overrides this method in order to reroute the read request to the
  1599.   appropriate routine in the VREC unit.
  1600. See Also
  1601.   FBrowser.GetRecord
  1602.  
  1603.  
  1604. ------- Procedures and Functions -------------------------------------------
  1605.  
  1606.  
  1607. FBROWSE also provides the following procedures, functions, and variables:
  1608.  
  1609.  
  1610. Variables
  1611.  
  1612.     RefreshPeriod : Word = 18*5;
  1613.  
  1614.   This typed constant tells the RefreshPeriodically function how often to
  1615.   check to see if the display needs to be refreshed. The value is in clock
  1616.   ticks (roughly 18/second), so the default setting requests that checks be
  1617.   made every five seconds.
  1618.  
  1619.  
  1620. Declaration
  1621.   function NullFilterFunc(RecNum : LongInt; Key : IsamKeyStr;
  1622.                           FBP : FBrowserPtr) : Boolean;
  1623. Purpose
  1624.   Do-nothing record filtering function.
  1625. Description
  1626.   The default record filtering function. It always returns True, indicating
  1627.   that the record in question should be displayed.
  1628. See Also
  1629.   FBrowser.SetFilterFunc
  1630.  
  1631.  
  1632. Declaration
  1633.   function NullRefreshFunc(FBP : FBrowserPtr) : Boolean;
  1634. Purpose
  1635.   Do-nothing refresh function.
  1636. Description
  1637.   The default refresh function. It always returns False, indicating
  1638.   that the display does not need to be refreshed.
  1639. See Also
  1640.   FBrowser.SetRefreshFunc
  1641.  
  1642.  
  1643. Declaration
  1644.   function RefreshAtEachCommand(FBP : FBrowserPtr) : Boolean;
  1645. Purpose
  1646.   Check for need to refresh before each command if no keystrokes pending.
  1647. Description
  1648.   This refresh function checks to see if a keystroke is waiting to be
  1649.   processed and, if not, it calls the PageStackValid function in the FILER
  1650.   unit. If PageStackValid is called and it returns StateInvalid,
  1651.   RefreshAtEachCommand returns True, otherwise False.
  1652.  
  1653.   Important: The technique used by RefreshAtEachCommand is not guaranteed to
  1654.   detect changes to existing records made by other workstations, only
  1655.   additions and deletions. It will detect changes only if the change alters
  1656.   the set of index keys currently used by the browser (see GetKeyNumber).
  1657. See Also
  1658.   FBrowser.SetRefreshFunc
  1659.  
  1660.  
  1661. Declaration
  1662.   function RefreshPeriodically(FBP : FBrowserPtr) : Boolean;
  1663. Purpose
  1664.   Check for need to refresh every RefreshPeriod clock ticks.
  1665. Description
  1666.   This refresh function sits in a loop waiting for a key to be pressed. Every
  1667.   RefreshPeriod clock ticks (= 5 seconds by default), it calls the
  1668.   PageStackValid function in the FILER unit. If PageStackValid returns
  1669.   StateInvalid, RefreshPeriodically exits immediately with a function result
  1670.   of True. Otherwise it continues looping until a key is pressed, in which
  1671.   case it returns False.
  1672.  
  1673.   Important: The technique used by RefreshPeriodically is not guaranteed to
  1674.   detect changes to existing records made by other workstations, only
  1675.   additions and deletions. It will detect changes only if the change alters
  1676.   the set of index keys currently used by the browser (see GetKeyNumber).
  1677. See Also
  1678.   FBrowser.SetRefreshFunc  RefreshPeriod
  1679.